
# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Utility classes and methods for use with simplejson and appengine.

Provides both a specialized simplejson encoder, GqlEncoder, designed to simplify
encoding directly from GQL results to JSON. A helper function, encode, is also
provided to further simplify usage.

  GqlEncoder: Adds support for GQL results and properties to simplejson.
  encode(input): Direct method to encode GQL objects as JSON.
"""

import datetime
from django.utils import simplejson

from time import strftime

from google.appengine.api import users
from google.appengine.ext import db

class HookedModel(db.Model):
    """A subclass of model that provides hooks for extra checks. From http://blog.appenginefan.com/"""
    
    def pre_write(self):
        """Called before a model is written to the store."""
        pass
    
    def _populate_internal_entity(self, *args, **kwds):
        """Introduces hooks into the entity storing process."""
        self.pre_write()
        return db.Model._populate_internal_entity(self, *args, **kwds)

class GqlEncoder(simplejson.JSONEncoder):
  
    """Extends JSONEncoder to add support for GQL results and properties.
  
    Adds support to simplejson JSONEncoders for GQL results and properties by
    overriding JSONEncoder's default method.
    """
  
    # TODO Improve coverage for all of App Engine's Property types.

    def default(self, obj):
    
        """Tests the input object, obj, to encode as JSON."""

        if hasattr(obj, '__json__'):
            return getattr(obj, '__json__')()

        if isinstance(obj, db.GqlQuery):
            return list(obj)

        elif isinstance(obj, db.Query):
            l = list(obj)
            return {'length' : len(l), 'items' : l }

        elif isinstance(obj, datetime.datetime):
            return obj.strftime("%Y-%m-%dT%H:%M:%S")
        
        elif isinstance(obj, datetime.date):
            return obj.strftime("%Y-%m-%d")

        elif isinstance(obj, db.Model):
            properties = obj.properties().items()
            output = {}
            output['id'] = obj.key().id_or_name()
            for field, values in properties:
                output[field] = getattr(obj, field)
            return output

        return simplejson.JSONEncoder.default(self, obj)


def encodeToJSON(input):
        """Encode an input GQL object as JSON
    
        Args:
          input: A GQL object or DB property.
    
        Returns:
          A JSON string based on the input object. 
          
        Raises:
          TypeError: Typically occurs when an input object contains an unsupported
            type.
        """
        return GqlEncoder().encode(input)
